package com.universest.swordholder.viewmodel.passage_editor

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.*
import androidx.compose.material.icons.filled.*
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.getSelectedText
import androidx.compose.ui.text.input.getTextAfterSelection
import androidx.compose.ui.text.input.getTextBeforeSelection
import androidx.lifecycle.viewModelScope
import androidx.room.withTransaction
import com.universest.swordholder.R
import com.universest.swordholder.aitool.Message
import com.universest.swordholder.aitool.PromptTask
import com.universest.swordholder.aitool.createAiTask
import com.universest.swordholder.data.dao.*
import com.universest.swordholder.data.*
import com.universest.swordholder.data.repository.*
import com.universest.swordholder.getApplicationContext
import com.universest.swordholder.model.NovelExporter
import com.universest.swordholder.model.NovelInfoHelper
import com.universest.swordholder.model.NovelSummaryHelper
import com.universest.swordholder.model.config.ConfigItem
import com.universest.swordholder.model.prompt.DEFAULT_WRITING_REQUIREMENTS
import com.universest.swordholder.model.textaction.*
import com.universest.swordholder.task.AbstractTask
import com.universest.swordholder.task.DirectTask
import com.universest.swordholder.task.NeedPrepareTask
import com.universest.swordholder.task.Task
import com.universest.swordholder.task.combineTasks
import com.universest.swordholder.tools.*
import com.universest.swordholder.viewmodel.BaseViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*


/**
 * PassageEditorViewModel 是一个用于管理文本编辑器状态的 ViewModel。
 *
 * 它负责维护当前输入框的内容、历史记录以及可执行的文本操作列表（如撤销/重做），
 * 并提供相关的业务逻辑方法供 UI 层调用。
 *
 */
class PassageEditorViewModel(intent: Intent? = null) : BaseViewModel(intent) {

    private val _uiEvent = MutableSharedFlow<UiEvent>()
    val uiEvent = _uiEvent.asSharedFlow()

    private val _toasts = MutableSharedFlow<String>()
    val toasts = _toasts.asSharedFlow()

    sealed class UiEvent {
        object ShowActionBarDialog : UiEvent()
        object Exit : UiEvent()
        object ShowPassageListDialog : UiEvent()
        object ClosePassageListDialog : UiEvent()
        object ShowAddVolumeDialog : UiEvent()
        object FocusEditTitle : UiEvent()
        object ShowSummarizeDialog : UiEvent()
        object OpenAiDialog: UiEvent()
    }

    private val _textValue = MutableStateFlow(TextFieldValue())

    private val _passageTitle = MutableStateFlow(TextFieldValue())

    /**
     * 当前文本框内容的状态流，供 Compose UI 监听使用。
     */
    val textValue: StateFlow<TextFieldValue> = _textValue.asStateFlow()

    val editPassageTitle: StateFlow<TextFieldValue> = _passageTitle.asStateFlow()

    private val _currentPassage: MutableStateFlow<Passage?> = MutableStateFlow(null)

    val currentPassage: StateFlow<Passage?> = _currentPassage.asStateFlow()

    private val _textActions = MutableStateFlow<List<TextAction>>(emptyList())

    /**
     * 可执行的文本操作列表（例如撤销、重做等），供 UI 显示按钮或菜单项。
     */
    val textActions = _textActions.asStateFlow()

    val bookId = getIntExtra("bookId", -1)

    val bookRepository = BookRepository(getUserDb())

    val passageRepository = PassageRepository(getUserDb())

    val volumeRepository = VolumeRepository(getUserDb())

    val longTextRepository = LongTextRepository(getUserDb())

    val book = bookRepository.getBookById(bookId)
        .map {
            it ?: Book(bookId = -1, bookName = "Error")
        }
        .stateIn(
            scope = viewModelScope,
            initialValue = null,
            started = SharingStarted.Companion.Eagerly
        )

    val volumes = volumeRepository.getVolumeByBookId(bookId)

    val passages = passageRepository.getPassagesByBookId(bookId)

    private var _passageSwitching = MutableStateFlow(false)

    val passageSwitching: StateFlow<Boolean> = _passageSwitching.asStateFlow()

    private val _history: TextEditHistory = TextEditHistory(textValue.value)

    private var restBookCharCount = -1

    private val _tasks = mutableStateListOf<AbstractTask<*,*>>()

    val tasks: List<AbstractTask<*,*>>
        get() = _tasks
    /**
     * 初始化 ViewModel：
     * - 添加初始文本值到历史记录中；
     * - 获取默认文本操作列表，并手动插入“撤销”和“重做”的操作项；
     * - 设置这些操作是否可用的条件及其行为。
     */
    init{
        val actionList = getTextActionList(getApplicationContext())
        val list = ArrayList<TextAction>(actionList.size + 2)
        list.add(
            TextAction(
                "撤销",
                Icons.AutoMirrored.Filled.Undo,
                { _history.hasHistory() },
                { textValue -> undo();null })
        )
        list.add(
            TextAction(
                "重做",
                Icons.AutoMirrored.Filled.Redo,
                { _history.canRedo() },
                { textValue -> redo();null })
        )
        list.addAll(actionList)
        list.add(TextAction("AI", Icons.Default.SmartToy, { true }, { textValue -> openAiDialog();null }))
        list.add(
            TextAction(
                "配置",
                Icons.Default.Settings,
                { true },
                { textValue -> viewModelScope.launch { _uiEvent.emit(UiEvent.ShowActionBarDialog) };null })
        )
        _textActions.value = list
        switchToLastBrowsePassage()
    }

    private fun switchToLastBrowsePassage() {
        viewModelScope.launch {
            val passageId = getLastBrowsePassageId()
                .firstOrNull()
            if(passageId != null && passageId != -1){
                switchPassage(passageId)
            }else{
                passages.firstOrNull()?.firstOrNull()?.let { switchPassage(it.passageId) }
            }
        }
    }

    private suspend fun computeRestBookCharCount(){
        val currentId = _currentPassage.value?.passageId ?: -1
        restBookCharCount = withContext(Dispatchers.IO) {
            passages.first().filter { it.passageId != currentId }.sumOf { it.charCount }
        }
    }

    private suspend fun switchPassageSuspend(passageId: Int){
        // 设置段落切换状态为true，表示正在切换中
        _passageSwitching.value = true

        // 获取指定ID的段落信息
        var passage = passageRepository.getPassageById(passageId).firstOrNull()
        if (passage != null) {
            // 获取段落对应的内容文本
            var longText = longTextRepository.getTextById(passage.contentId).firstOrNull()

            // 如果内容文本不存在，则创建新的空文本并更新段落信息
            if(longText == null){
                longText = LongText(content = "")
                longText = longText.copy(textId = longTextRepository.insert(longText).toInt())
                passage = passage.copy(contentId = longText.textId)
                passageRepository.update(passage)
            }

            // 更新文本内容和历史记录
            _textValue.value = TextFieldValue(longText.content)
            _history.resetHistory(_textValue.value)

            // 更新段落标题
            _passageTitle.value = TextFieldValue(passage.title)
        }else{
            _textValue.value = TextFieldValue()
            _history.resetHistory(_textValue.value)
            _passageTitle.value = TextFieldValue()
        }

        // 更新当前段落并重新计算剩余字数
        _currentPassage.value = passage
        computeRestBookCharCount()

        // 设置段落切换状态为false，表示切换完成
        _passageSwitching.value = false
        bookRepository.updateLastBrowsePassageId(bookId, passageId)
    }

    /**
     * 切换到指定ID的段落
     * @param passageId 要切换到的段落ID
     */
    private fun switchPassage(passageId: Int,then:(() -> Unit)? = null){
        viewModelScope.launch {
            switchPassageSuspend(passageId)
            then?.invoke()
        }
    }

    /**
     * 撤销上一次的操作，将文本恢复至上一历史节点。
     * 若无更早的历史记录则不做处理。
     */
    fun undo(){
        _history.undo()?.let { _textValue.value = it }
    }

    /**
     * 重做被撤销的操作，前进至下一历史节点。
     * 若已处于最新历史位置则不做处理。
     */
    fun redo(){
        _history.redo()?.let { _textValue.value = it }
    }

    /**
     * 更新当前文本内容并将其加入历史记录栈。
     * 如果在中间历史点进行修改，则会清除后续所有历史记录。
     * 历史记录数量超过最大限制时，移除最早的一条记录。
     *
     * @param inputValue 新的文本框内容
     */
    fun updateTextValue(inputValue: TextFieldValue) {
        if (inputValue == textValue.value) return
        val newValue = if (autoIndent.value && isInsertNewLine(textValue.value, inputValue)){
            //实现自动缩进功能，插入新行时自动缩进。
            val str = inputValue.getStringLineAtIndex(textValue.value.selection.start)
            val nonWhiteStart = str.indexOfFirst { !it.isWhitespace() }
            val indent = str.substring(0,if(nonWhiteStart != -1) nonWhiteStart else str.length)
            //继承上一行的缩进
            val newText = inputValue.text.substring(0,
                inputValue.selection.start) + indent + inputValue.text.substring(inputValue.selection.start)
            val newSelection = TextRange(inputValue.selection.start + indent.length)
            TextFieldValue(newText,newSelection)
        }else{
            inputValue
        }
        _textValue.value = newValue
        _history.addHistory(newValue)
        val newText = newValue.text
        val passage = _currentPassage.value?.copy(charCount = newText.count{!it.isWhitespace()})
        viewModelScope.launch {
            if(passage != null) {
                longTextRepository.update(LongText(passage.contentId, newText))
                passageRepository.update(passage)
                bookRepository.updateCharCount(bookId, passage.charCount + restBookCharCount)
            }
        }
    }

    fun openAiDialog(){
        viewModelScope.launch {
            _uiEvent.emit(UiEvent.OpenAiDialog)
        }
    }

    private fun isInsertNewLine(oldValue: TextFieldValue, newValue: TextFieldValue): Boolean {
        // 检查文本长度是否只增加了1（回车符的长度）
        if (newValue.text.length != oldValue.text.length + 1) {
            return false
        }

        // 检查新增的字符是否是换行符
        val oldText = oldValue.text
        val newText = newValue.text
        val selectionStart = oldValue.selection.start

        // 确保在光标位置插入了一个换行符
        return if (selectionStart < oldText.length) {
            // 在文本中间插入
            newText[selectionStart] == '\n' &&
                    newText.substring(0, selectionStart) == oldText.substring(0, selectionStart) &&
                    newText.substring(selectionStart + 1) == oldText.substring(selectionStart)
        } else {
            // 在文本末尾插入
            newText[selectionStart] == '\n' &&
                    newText.substring(0, selectionStart) == oldText
        }
    }

    /**
     * 执行指定的文本操作。
     * 调用该操作对应的执行器函数，并根据结果更新文本内容。
     *
     * @param textAction 需要被执行的文本操作对象
     */
    fun applyTextAction(textAction: TextAction){
        try {
            val newValue = textAction.executor(textValue.value)
            if (newValue != null) {
                updateTextValue(newValue)
            }
        }catch (e: Throwable){
            Log.e("PassageEditorViewModel", "applyTextAction error: $e")
        }
    }

    private var _configManager = PassageEditorConfigManager()

    val configItems = _configManager.configItem

    fun getUserConfig(key: String, defaultValue: String): Flow<String> {
        return _configManager.getUserConfig(key, defaultValue)
    }

    fun getUserConfig(configItem: ConfigItem): StateFlow<String> {
        return _configManager.getUserConfig(configItem)
            .stateIn(scope = viewModelScope,
                started = SharingStarted.Companion.Eagerly,
                initialValue = configItem.defaultValue)
    }

    fun setUserConfig(configItem: ConfigItem, value: String) {
        viewModelScope.launch {
            try {
                _configManager.setUserConfig(configItem,value)
            }catch (e: Throwable){
                Log.e("PassageEditorViewModel", "setUserConfig error: $e")
            }
        }
    }

    val showCharCount: StateFlow<Boolean>
        get(){
            return getUserConfig("showCharCount","true").map { it.normallyToBoolean() }
                .stateIn(scope = viewModelScope, started = SharingStarted.Companion.Eagerly, initialValue = true)
        }

    val showActionBarText: StateFlow<Boolean>
        get(){
            return getUserConfig("showActionBarText","true").map { it.normallyToBoolean() }
                .stateIn(scope = viewModelScope, started = SharingStarted.Companion.Eagerly, initialValue = true)
        }

    val actionBarAlwaysShow: StateFlow<Boolean>
        get(){
            return getUserConfig("actionBarAlwaysShow","false").map { it.normallyToBoolean() }
                .stateIn(scope = viewModelScope, started = SharingStarted.Companion.Eagerly, initialValue = false)
        }

    val autoIndent: StateFlow<Boolean>
        get(){
            return getUserConfig("autoIndent","true").map { it.normallyToBoolean() }
            .stateIn(scope = viewModelScope, started = SharingStarted.Companion.Eagerly, initialValue = true)
        }
    /**
     * 创建新的卷
     * @param name 卷的名称
     */
    suspend fun createNewVolumeSuspend(name: String){
        // 获取当前所有卷，确定新卷的排序位置
        val vols = volumes.first()
        val order = if(vols.isEmpty()) 0 else vols.last().order + 1
        val volume = Volume(name = name, order = order, bookId = bookId)
        volumeRepository.insert(volume)
    }

    suspend fun updateVolumeNameSuspend(volumeId:Int,name: String){
        val volume = volumeRepository.getVolumeById(volumeId).firstOrNull()
        volume?.let {
            volumeRepository.update(it.copy(name = name))
        }
    }


    /**
     * 创建新的段落
     * @param name 段落的标题
     */
    suspend fun createNewPassage(name: String){
        // 获取当前卷和段落信息，确定新段落的排序位置和所属卷
        val vols = volumes.first()
        val volId = if(vols.isEmpty()) -1 else vols.last().volumeId
        val passages = getPassagesUnderVolume(volId).first()
        val order = if(passages.isEmpty()) 0 else passages.last().order + 10
        val passage = Passage(title = name, volumeId = volId, order = order, bookId = bookId)
        val newPassageId = passageRepository.insert(passage).toInt()
        switchPassage(newPassageId){
            viewModelScope.launch {
                _uiEvent.emit(UiEvent.FocusEditTitle)
                _uiEvent.emit(UiEvent.ClosePassageListDialog)
            }
        }
    }

    fun getPassagesUnderVolume(volumeId: Int): Flow<List<Passage>> {
        return passages.map { passages ->
            passages.filter { it.volumeId == volumeId }
        }
    }

    private fun getLastBrowsePassageId(): Flow<Int> {
        return bookRepository.getBookById(bookId)
            .map { book -> book?.lastBrowsePassageId ?: -1 }
    }

    fun changePassage(passageId: Int){
        viewModelScope.launch {
            if(_passageSwitching.value)return@launch
            switchPassage(passageId)
        }
    }

    fun updatePassageTitle(title: TextFieldValue){
        _passageTitle.value = title
        val newPassage = _currentPassage.value?.copy(title = title.text)
        _currentPassage.value = newPassage
        viewModelScope.launch {
            if(newPassage!=null) {
                getUserDb().withTransaction {
                    passageRepository.update(newPassage)
                    val book = bookRepository.getBookById(newPassage.bookId).firstOrNull()
                    if(book?.singlePassage == true){
                        bookRepository.updateBook(book.copy(bookName = newPassage.title))
                    }
                }
            }
        }
    }

    fun changePassageListShown(open: Boolean = true){
        viewModelScope.launch {
            _uiEvent.emit(if(open)UiEvent.ShowPassageListDialog else UiEvent.ClosePassageListDialog)
        }
    }

    fun openNewVolumeDialog(){
        viewModelScope.launch {
            _uiEvent.emit(UiEvent.ShowAddVolumeDialog)
        }
    }

    fun passageListItemSwap(passageIdA: Int, passageIdB: Int){
        viewModelScope.launch {
            passageRepository.swapPassageOrder(passageIdA, passageIdB)
        }
    }

    fun movePassageToAnotherVolume(passageId: Int, volumeId: Int,top: Boolean) {
        viewModelScope.launch {
            passageRepository.movePassageToAnotherVolume(passageId, volumeId,top)
        }
    }

    fun swapVolumeOrder(volumeIdA: Int, volumeIdB: Int){
        viewModelScope.launch {
            volumeRepository.swapVolumeOrder(volumeIdA, volumeIdB)
        }
    }

    fun autoChangeVolumePassageName() {
        viewModelScope.launch {
            getUserDb().withTransaction {
                try {
                    val volumes = volumes.first()
                    volumes.forEachIndexed { index, volume ->
                        // 提取真正的原始内容（去掉所有数字卷标识）
                        val originalName = volume.name.replace("""^第[一二三四五六七八九十百千万亿兆两零\d]+卷""".toRegex(), "")
                        val newVolume = volume.copy(name = "第${index + 1}卷 $originalName")
                        volumeRepository.update(newVolume)

                        val passages = passageRepository.getPassagesByBookIdAndVolumeId(
                            bookId, volume.volumeId
                        ).first()

                        passages.forEachIndexed { passageIndex, passage ->
                            // 提取真正的原始内容（去掉所有数字章标识）
                            val originalTitle = passage.title.replace("""^第[一二三四五六七八九十百千万亿兆两零\d]+[章回篇]""".toRegex(), "")
                            val newPassage = passage.copy(title = "第${passageIndex + 1}章 $originalTitle")
                            passageRepository.update(newPassage)
                        }
                    }
                } catch (e: Exception) {
                    Log.e("PassageEditorViewModel", "autoChangeVolumePassageName: ", e)
                    throw e
                }
            }
        }
    }

    fun exportNovel(){
        val exporter = NovelExporter(bookId)
        val task = exporter.createTask()
        _tasks.add(task)
        viewModelScope.launch {
            val result = task.execute(Unit)
            _tasks.remove(task)
            when(result.isSuccess){
                true -> {
                    _toasts.emit(
                        getApplicationContext().getString(
                            R.string.export_txt_success,
                            result.getOrNull() ?: ""
                        ))
                }
                false -> {
                    _toasts.emit(
                        getApplicationContext().getString(
                            R.string.export_txt_failed,
                            result.exceptionOrNull() ?: ""
                        ))
                }
            }
        }
    }

    fun copyPassage(){
        val text = _textValue.value.text
        if(text.isNotEmpty()){
            val clipboardManager = getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
            val clipData = ClipData.newPlainText("text", text)
            clipboardManager.setPrimaryClip(clipData)
            viewModelScope.launch {
                _toasts.emit("复制成功")
            }
        }
    }

    fun removeVolume(volumeId: Int){
        viewModelScope.launch {
            val passages = passageRepository.getPassagesByBookIdAndVolumeId(bookId, volumeId).firstOrNull()?:emptyList()
            val task = Task<Unit, Unit>(name = "删除卷", progressMaxValue = passages.size){
                passages.forEachIndexed { index,passage->
                    updateMessage("正在删除 ${passage.title}")
                    removePassageSuspend(passage.passageId)
                    updateProgress(index+1,passages.size)
                }
                volumeRepository.deleteById(volumeId)
            }.withContext(Dispatchers.Main)

            _tasks.add(task)
            task.execute(Unit)
            _tasks.remove(task)
        }
    }

    fun removePassage(passageId: Int){
        viewModelScope.launch {
            removePassageSuspend(passageId)
        }
    }

    private suspend fun removePassageSuspend(passageId: Int){
        if(_currentPassage.value?.passageId == passageId){
            val newPassageId = getNearestPassageId(passageId)
            switchPassageSuspend(newPassageId)
        }
        val passage = passageRepository.getPassageById(passageId).firstOrNull()
        if(passage != null){
            longTextRepository.deleteById(passage.contentId)
            passageRepository.deleteById(passage.simpleContentId)
        }
        passageRepository.deleteById(passageId)
    }

    private suspend fun getNearestPassageId(passageId: Int): Int{
        val passageIds = passages.firstOrNull()?.map { it.passageId }?:emptyList()
        val index = passageIds.indexOf(passageId)
        if(index < 0){
            return passageIds.firstOrNull()?:-1
        }
        if(index == passageIds.size - 1 && index > 0){
            return passageIds[index - 1]
        }
        if(index+1 < passageIds.size){
            return passageIds[index + 1]
        }
        return -1
    }

    fun getSummarizedText(passage: Passage): Flow<String>{
        return longTextRepository.getTextById(passage.simpleContentId)
            .map { it?.content?:""}
    }

    fun getSummarizedText(volume: Volume): Flow<String>{
        return longTextRepository.getTextById(volume.summaryId)
            .map { it?.content?:""}
    }

    fun saveSummarizedText(volume: Volume, text: String){
        viewModelScope.launch {
            saveSummarizedTextSuspend(volume, text)
        }
    }

    fun saveSummarizedText(passage: Passage, text: String){
        viewModelScope.launch {
            saveSummarizedTextSuspend(passage, text)
        }
    }

    private suspend fun saveSummarizedTextSuspend(passage: Passage, text: String){
        if(passage.simpleContentId == -1){
            passageRepository.update(passage.copy(
                simpleContentId = longTextRepository.insert(LongText(content = text)).toInt()
            ))
        }else{
            longTextRepository.update(LongText(
                textId = passage.simpleContentId,
                content = text
            ))
        }
    }

    private suspend fun saveSummarizedTextSuspend(volume: Volume, text: String){
        if(volume.summaryId == -1){
            volumeRepository.update(volume.copy(
                summaryId = longTextRepository.insert(LongText(content = text)).toInt()
            ))
        }else{
            longTextRepository.update(LongText(
                textId = volume.summaryId,
                content = text
            ))
        }
    }

    fun showSummarizeDialog(){
        viewModelScope.launch {
            _uiEvent.emit(UiEvent.ShowSummarizeDialog)
        }
    }

    suspend fun getNonSummaryPassagesBefore(): List<Passage>{
        val helper = NovelSummaryHelper(bookId)
        val list = helper.getNonSummaryPassagesBefore(_currentPassage.value?.passageId?:-1)
        return list
    }

    fun setVolumeUseSummary(volume: Volume,useSummary: Boolean){
        viewModelScope.launch {
            volumeRepository.update(volume.copy(summaryUse = useSummary))
        }
    }

    suspend fun getNonSummaryPassagesNeed(volume: Volume): List<Passage>{
        val helper = NovelSummaryHelper(bookId)
        val infoHelper = NovelInfoHelper(bookId)
        val list = mutableListOf<Passage>()
        val passages = passageRepository.getPassagesByBookIdAndVolumeId(bookId, volume.volumeId).firstOrNull()?:emptyList()
        val passage = passages.firstOrNull()
        if(passage == null)return emptyList()
        list.addAll(helper.getNonSummaryPassagesBefore(passage.passageId))
        list.addAll(passages.filter {
            infoHelper.getPassageSummary(it.passageId).isBlank()
        })
        return list
    }

    fun summaryCurrentPassage(){
        val novelSummaryHelper = NovelSummaryHelper(bookId)
        val novelInfoHelper = NovelInfoHelper(bookId)
        val passage = _currentPassage.value
        if(passage == null)return
        val task = novelSummaryHelper.createGenerateSummaryTask(passage.passageId, novelInfoHelper)
            .combineTask(name = "摘要 ${passage.title}") {
                novelInfoHelper.setPassageSummary(passage.passageId, it)
                updateCurrentPassage()
            }
        viewModelScope.launch {
            _tasks.add(task)
            task.execute(Unit)
            _tasks.remove(task)
        }
    }

    suspend fun summaryVolumeSuspend(volume: Volume): String{
        val novelSummaryHelper = NovelSummaryHelper(bookId)
        val novelInfoHelper = NovelInfoHelper(bookId)
        val task = novelSummaryHelper.createSummaryVolumeTask(volume.volumeId, novelInfoHelper)
        _tasks.add(task)
        val result = task.execute(Unit)
        _tasks.remove(task)
        if(result.isFailure){
            _toasts.emit("生成摘要失败：${result.exceptionOrNull()?.message?:""}")
            return ""
        }
        return result.getOrNull()?:""
    }

    suspend fun summaryPassagesSuspend(passages: List<Passage>){
        val novelSummaryHelper = NovelSummaryHelper(bookId)
        val novelInfoHelper = NovelInfoHelper(bookId)
        val task = combineTasks(name = "生成摘要",tasks = passages.map { passage->
            novelSummaryHelper.createGenerateSummaryTask(passage.passageId, novelInfoHelper)
                .combineTask(name = "摘要 ${passage.title}") {
                    novelInfoHelper.setPassageSummary(passage.passageId, it)
                    if(passage.passageId == _currentPassage.value?.passageId){
                        updateCurrentPassage()
                    }
                }
        })
        _tasks.add(task)
        val result = task.execute(Unit)
        if(result.isFailure){
            _toasts.emit("生成摘要失败：${result.exceptionOrNull()?.message?:""}")
        }
        _tasks.remove(task)
    }

    fun summaryPassages(withCurrent: Boolean = true){
        val task = NeedPrepareTask("生成摘要",
            prepareTask = Task<Unit, AbstractTask<Unit, Unit>>("准备生成"){
                val novelSummaryHelper = NovelSummaryHelper(bookId)
                val novelInfoHelper = NovelInfoHelper(bookId)
                val beforeList = novelSummaryHelper.getNonSummaryPassagesBefore(_currentPassage.value?.passageId?:-1)
                val list = mutableListOf<Passage>()
                list.addAll(beforeList)
                if(withCurrent) {
                    _currentPassage.value?.let {
                        list.add(it)
                    }
                }
                combineTasks("生成摘要", list.map { passage->
                    novelSummaryHelper.createGenerateSummaryTask(passage.passageId, novelInfoHelper)
                        .combineTask { summary ->
                            novelInfoHelper.setPassageSummary(passage.passageId, summary)
                            if(passage.passageId == _currentPassage.value?.passageId){
                                updateCurrentPassage()
                            }
                        }
                })
        })
        viewModelScope.launch {
            _tasks.add(task)
            val result = task.execute(Unit)
            if(result.isFailure){
                _toasts.emit("生成摘要失败：${result.exceptionOrNull()?.message?:""}")
            }
            _tasks.remove(task)
        }
    }

    private suspend fun updateCurrentPassage(){
        _currentPassage.value?.let { _currentPassage.value = passageRepository.getPassageById(it.passageId).firstOrNull() }
    }

    /**
     * 计算当前段落在整个书籍段落列表中的索引位置
     *
     * 该方法考虑了书籍中段落可能属于不同卷的情况，按以下规则计算索引：
     * 1. 如果段落不属于任何卷（volumeId == -1），直接在未分卷段落列表中查找索引
     * 2. 如果段落属于某个卷，则需要计算前面所有卷及其中段落的数量，再加上在当前卷内的索引
     *
     * @return 当前段落在整个书籍段落列表中的索引位置，从0开始计数；如果未找到或出错则返回-1
     */
    suspend fun computeCurrentPassageIndexInList(): Int {
        val passage = _currentPassage.value
        if (passage == null) return -1
        
        // 处理没有归属任何卷的段落
        if (passage.volumeId == -1) {
            val nonVolumePassages =
                passageRepository.getPassagesByBookIdAndVolumeId(bookId, -1).firstOrNull()
                    ?: emptyList()
            return nonVolumePassages.indexOfFirst { it.passageId == passage.passageId }
        }
        
        // 获取段落所在卷的信息
        val volume = volumeRepository.getVolumeById(passage.volumeId).firstOrNull()
        if (volume == null) return -1
        
        // 查找段落在其所属卷内的索引
        val indexInVolume =
            passageRepository.getPassagesByBookIdAndVolumeId(bookId, volume.volumeId).firstOrNull()
                ?.indexOfFirst { it.passageId == passage.passageId } ?: -1
        if (indexInVolume == -1) return -1
        
        // 计算段落在所有卷之前的段落总数
        val volumes = volumes.firstOrNull() ?: emptyList()
        val volumeIndex = volumes.indexOfFirst { it.volumeId == volume.volumeId }
        var sum = 0
        
        // 遍历当前卷之前的所有卷，累加它们包含的段落数量以及卷的数量
        for (i in 0 until volumeIndex) {
            val size = passageRepository.getPassagesByBookIdAndVolumeId(bookId, volumes[i].volumeId)
                .firstOrNull()?.size ?: 0
            sum += size
            sum += 1  // 加1是因为每个卷本身也要占一个位置
        }
        
        // 返回总索引：前面所有段落数 + 当前段落在卷内索引 + 1(卷本身的位置)
        return sum + indexInVolume + 1
    }

    fun aiActionResultHandle(result: String){
        val textBefore = _textValue.value.getStringBeforeSelection()
        val textAfter = _textValue.value.getStringAfterSelection()
        val textMiddle = result.passageFormat()
        val text = textBefore + textMiddle + textAfter
        val range = TextRange(textBefore.length, textBefore.length + textMiddle.length)
        updateTextValue(TextFieldValue(text, range))
    }

    suspend fun runAiActionSuspend(action: AiAction,vararg params: String): String{
        val task = NeedPrepareTask<Unit, String>(
            name = "AI操作",
            prepareTask = Task<Unit, AbstractTask<Unit, String>>("准备AI操作"){
                val novelInfoHelper = NovelInfoHelper(bookId)
                val param: PromptParams = when(action.type){
                    AiActionType.GENERATE_TEXT ->
                        GenerateTextParams(
                            novelInfo = novelInfoHelper.getNovelInfo(),
                            previousChapters = novelInfoHelper.getPreviousChapterSummaries(_currentPassage.value?.passageId?:-1,3,bookId),
                            currentChapter = _textValue.value.getStringBeforeSelection(),
                            writingRequirements = DEFAULT_WRITING_REQUIREMENTS,
                            contentRequirements = params[0],
                            continueContent = _textValue.value.getStringAfterSelection()
                        )
                    AiActionType.REWRITE_TEXT ->
                        RewriteTextParams(
                            novelInfo = novelInfoHelper.getNovelInfo(),
                            previousChapters = novelInfoHelper.getPreviousChapterSummaries(_currentPassage.value?.passageId?:-1,3,bookId),
                            currentChapter = _textValue.value.getStringBeforeSelection(),
                            writingRequirements = params[0],
                            paragraph = _textValue.value.getSelectedText().toString(),
                            continueContent = _textValue.value.getStringAfterSelection()
                        )
                    AiActionType.COMMENT ->
                        CommentParams(
                            novelInfo = novelInfoHelper.getNovelInfo(),
                            previousChapters = novelInfoHelper.getPreviousChapterSummaries(_currentPassage.value?.passageId?:-1,3,bookId),
                            currentChapter = _textValue.value.toString(),
                            selectedParagraph = _textValue.value.getSelectedText().toString(),
                            question = params[0]
                        )
                }
                val messageList = action.prompt.toMessageList(param.toMap())
                DirectTask<Unit, List<Message>>("AI操作",obj = messageList)
                    .combineTask("调用大模型", createAiTask("AI操作"))
                    .convert { it->it.content }
            }
        )
        _tasks.add(task)
        val result = task.execute(Unit)
        _tasks.remove(task)
        if(result.isFailure){
            _toasts.emit("AI操作失败：${result.exceptionOrNull()?.message?:""}")
            return ""
        }else{
            return result.getOrNull()?:""
        }
    }
}